# ----------------------------------------------------------------------------
#       Copyright (C) 2013-2014 Huynh Vi Lam  <domovilam@gmail.com>
#
#       This file is part of pimucha.
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#	
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#	
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------

import logging
from piHAlibs import (serverthreads)
from piHAparsers import (CMDEncoders,cmdcheck,cmdencode)
from .corelibs import (alias2hu,huoralias,hu2alias,hudevice,huencoder,huorhexid)
from .servers import (INPUTq,MESSAGEq,SetupDaemons,TXControllers)


logger = logging.getLogger()

ParseCMDS = {}


def cmdinputh(data,ctrl=None):
    """
    data input : PROTOCOL HU FUNCTION
    convert HU to deviceId if need
    output = [protocol, houseunit(deviceId), function, (level)]
    ctrl = controller cmd send to 
    """
    if isinstance(data,list):
        a = data
    else:
        a = data.split()
    if len(a) < 3 : return 'Min three parameters needed'
    proto = a[0].upper()
    if proto not in CMDEncoders: return 'Error for the parameter protocol %s' % proto
    hu = huorhexid(a[1])
    if not hu:  return 'Error for the second parameter unit %s' % hu
    device,protocol = hudevice(hu)
    msg = ''
    if device:		#Update new protocol
        if huencoder(['device',hu,proto]):
            msg = 'Update succeeded for new encoder protocol'
        else:
            msg = 'Failed to update new encoder protocol'
    else:
        msg = 'No alias found in database'		
        device = hu
    phf = [proto,device,a[2]]
    args = cmdcheck(phf)
    if not args:
        return 'Failed to check HU FCT for input data %s' % data
    else:
        msg += '\nResult of parsing Input : %s - Alias : %s' % (repr(args),hu2alias(a[1]))
        if ctrl is None:
            return msg + '\n' + sendcmd(args,data)
        else:
            return msg + '\n' + sendcmdto(args,data,ctrl)
for p in CMDEncoders:
    ParseCMDS.setdefault(p)
    ParseCMDS[p]=cmdinputh


def cmdinputf(data):
    """
    data input : FUNCTION HU (or ALIAS)
    convert ALIAS to HU
    check HU / deviceId + protocol
    output = [protocol, houseunit(deviceId), function, (level)]
    """
    if isinstance(data,list):
        a = data
    else:
        a = data.split()
    logger.debug("Checking syntax of houseunit / alias %s",a[1])
    hu = huoralias(a[1])
    if hu is None:	#hu not referenced
        hu = a[1]
        alias = 'NoAlias'
    else:
        if hu != a[1]:	#input is alias
            alias = a[1]
        else:		#input is hu
            hu = hu.upper()
            alias = hu2alias(hu)
    device,protocol = hudevice(hu)
    if device:
        if (protocol is None) and (device.startswith('0x')):
            return 'Encode protocol is not set for device %s - hu %s' % (device,hu)
    else:
        device = hu
    if protocol is None:	#default protocol to PL
        protocol = 'PL'
    b = [protocol,device,a[0]]
    args = cmdcheck(b)
    if not args:
        return 'Failed to check FCT HU for input data %s' % data
    else:
        msg = 'Result of parsing Input : %s - Alias : %s' % (repr(args),alias)
        return msg + '\n' + sendcmd(args,data)
ParseCMDS.update({'ON':cmdinputf,'OFF':cmdinputf})


def sendcmd(args,data):
    #Encode
    cmd = cmdencode(args)
    if not cmd:
        return 'Failed to encode command with %s' % repr(data)
    #cmd = [[list txcontroller],idencoder,txcmdtosend]
    logger.debug('%s',(repr(cmd)))
    txctrls = cmd[0]
    for namedev in TXControllers: 	#Priority to local controller for first loop
        #Check thread alive
        tt = serverthreads(namedev)
        if tt:
            if not tt.isAlive(): continue
        else:
            continue
        targetctrl = namedev.split(':')[1]
        if targetctrl[0] == 'N': pass	#Pass net controller for first loop
        for ctrl in txctrls:
            if ctrl == targetctrl:
                TXControllers[namedev].loccmdq.put_nowait(cmd[1:])
                return "Putting cmd in local TX queue of controller %s" % namedev
            else:
                pass
    #If cmd not send local controller, make second loop and send to net controller
    for namedev in TXControllers:
        targetctrl = namedev.split(':')[1]
        if targetctrl[0] != 'N': pass 	#Pass local controller for second loop
        targetctrl = targetctrl[1:]
        for ctrl in txctrls:
            if ctrl == targetctrl:
                if isinstance(data,list) : data = ' '.join(data)
                TXControllers[namedev].netsend(data)
                return "Putting args in network TX queue of controller %s" % namedev
            else:
                pass
    else:
        return "No controller detected for sending command %s" % repr(data)


def sendcmdto(args,data,namedev):
    targetctrl = namedev.split(':')[1]
    #Encode
    cmd = cmdencode(args)
    if not cmd:
        return 'Failed to encode command with %s' % repr(data)
    logger.debug('%s',(repr(cmd)))
    #cmd = [[list txcontroller],idencoder,txcmdtosend]
    if targetctrl[0] == 'N':
        ctrl = targetctrl[1:]
    else:
        ctrl = targetctrl
    if ctrl in cmd[0]:
        if targetctrl[0] == 'N':
            if isinstance(data,list) : data = ' '.join(data)
            TXControllers[namedev].netsend(data)
            return "Putting args in network TX queue of controller %s" % namedev
        else:
            TXControllers[namedev].loccmdq.put_nowait(cmd[1:])
            return "Putting cmd in local TX queue of controller %s" % namedev
    else:
        return "Target controller %s differs with controllers needed for sending command %s" % (namedev,repr(cmd[0]))
